﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace System
{
	public static class ObjectExtension
	{
		private static readonly Dictionary<KeyValuePair<Type, PropertyInfo>, Func<object, object>> CachePropGetters
			= new Dictionary<KeyValuePair<Type, PropertyInfo>, Func<object, object>>();

		public static bool IsEquals(this object obj, object obj1)
		{
			return Equals(obj, obj1);
		}

		public static bool IsEqualsProperties(this object obj, object obj1)
		{
			Type self;
			return (obj == null && obj1 == null) || (obj != null && obj1 != null) && (self = obj.GetType()) == (obj1.GetType()) && self
				.GetProperties()
				.Select(s => CachePropGetters.GetOrAddDefault(new KeyValuePair<Type, PropertyInfo>(self, s), () => s.GetValueGetter<object>()))
				.All(s =>
					s(obj1).IsEquals(s(obj)));
		}

		public static int GetHashForProperties(this object obj)
		{
			Type self;
			return (obj == null) ? 0 : (self = obj.GetType())
				.GetProperties()
				.Select(s =>
					CachePropGetters.GetOrAddDefault(new KeyValuePair<Type, PropertyInfo>(self, s), () => s.GetValueGetter<object>()))
				.Select(s => s
					(obj).GetHashCode())
				.Aggregate((total, next) => total ^= next);
		}

		public static string GoString(this object obj)
		{
			return (obj != null) ? obj.ToString() : null;

		}

		public static bool IsDefault(this object subj)
		{
			Type type;
			return subj == null || (bool)Defaults.GetOrAddDefault(type = subj.GetType(), () =>
				typeof(TypeExtension).GetMethod("IsDefault")
				.MakeGenericMethod(new[] { type }).Invoke(null, new[] { subj }));
		}

		private static readonly Dictionary<Type, object> Defaults = new Dictionary<Type, object>();

		//public static T Is<T>(this T obj, Func<T, bool> condition, Exception ex)
		//{
		//    if (condition(obj))
		//        return obj;
		//    else
		//        throw ex ?? new Exception();
		//}

		//public static T Is<T>(this T obj, Func<T, bool> condition, string exMessage)
		//{
		//    return obj.Is(condition, new Exception(exMessage));
		//}

		//public static T IfThen<T>(this T obj, Func<T, bool> condition, Action<T> Then)
		//{
		//    if (condition(obj))
		//        Then(obj);
		//    return obj;
		//}

		//public static T IfElse<T>(this T obj, Func<T, bool> condition, Action<T> Else)
		//{
		//    if (!condition(obj))
		//        Else(obj);
		//    return obj;
		//}
	}
}
